SVN 的基本使用
SVN 是什么?
SVN(Subversion)是一款版本管理工具,把数据放置在一个中央资料档案(repository) 中。 这个档案库很像一个普通的文件服务器, 用户可以从这个服务器上下载和上传文件,不过它还会记住每一次文件的变动。 这样你就可以把档案恢复到旧的版本, 或是浏览文件的变动历史。
SVN 分会为两个部分,服务器部分和客户端部分,服务器部分的操作主要是由配置管理员完成,包括 SVN 服务器环境的搭建、版本库的创建、用户的创建与权限分配以及版本库数据的定期备份
这里补充一下 “检出” 操作:Checkout 操作是用来从版本库创建一个工作副本。工作副本是开发者私人的工作空间,可以进行内容的修改,然后提交到版本库中。
服务端的搭建
SVN 安装环境
SVN 和 Git 不同,它是需要一个中央服务器
输入 svn 命令检查是否安装了
安装 svn
sudo apt-get install subversion
# sudo mkdir /home/svn
# 这里也可以直接创建一个 svn 用户,让它进入 sudo 组,方便管理
su root
useradd mysvn -m -G sudo -c "svn manager user" -s /bin/bash
# sudo echo "password" | passwd --stdin svn
echo mysvn:123456 | chpasswd
# 检查是否安装成功
svn --version
服务端创建项目
su mysvn
cd /home/mysvn
# 创建项目仓库目录,在 SVN 根目录下创建一个新文件夹,作为项目仓库
mkdir /home/mysvn/rep
使用 svn 命令创建 SVN 文件仓库
svnadmin create /home/mysvn/rep
然后这个目录下会出现以下文件
SVN 配置文件
在这个项目里面 conf 下的 svnserve.conf
、passwd
、authz
这三个文件是用来配置当前项目的,主要包括用户名,密码,权限等
配置用户名密码
vim passwd
先来配置最简单的用户名和密码,在 passwd 中 [users]
下面,根据注释的样子配置,等于号前面的是用户名后面的是密码,用户名前不要空格,等于号两遍有空格
配置分组权限
版本库路径权限段的段名格式如下:
[<版本库名>:<路径>]
如下:
[groups]
g_admin = admin,thinker
[admintools:/]
@g_admin = rw
* =
[test:/home/thinker]
thinker = rw
* = r
vim authz
在 authz 中 [groups]
下面,配置一个叫做 develop 的分组,里面有两个用户 mysvn 和 alsritter,[/]
表示所有的目录,@
后面跟的是组名,这里是 @develop
等于号右边的 rw 表示读写权限都有
服务配置文件
svn 服务配置文件为版本库目录中的文件 conf/svnserve.conf
,该文件仅由一个 [general]
配置段组成。
anon-access:控制非鉴权用户访问版本库的权限,取值范围为 "write"、"read"和"none"。 即 "write" 为可读可写,"read" 为只读,"none" 表示无访问权限。 默认值:read
auth-access:控制鉴权用户访问版本库的权限。取值范围为"write"、"read"和"none"。 即"write"为可读可写,"read"为只读,"none"表示无访问权限。 默认值:write
authz-db:指定权限配置文件名,通过该文件可以实现以路径为基础的访问控制。 除非指定绝对路径,否则文件位置为相对conf目录的相对路径。 默认值:authz
realm:指定版本库的认证域,即在登录时提示的认证域名称。若两个版本库的 认证域相同,建议使用相同的用户名口令数据文件。 默认值:一个UUID(Universal Unique IDentifier,全局唯一标示)。
下面介绍几个主要的配置示例:
配置 svnserve.conf
文件,将
anon-access = none
auth-access = write
前面的 #
和空格去掉,第一行表示匿名用户的权限,配置的是无(默认是 read
),第二行表示认证用户的权限,我配置的是写
password-db = passwd
前面的 #
和空格去掉,表示使用用户名密码
authz-db = authz
前面的 #
和空格去掉,表示使用权限认证
启动 SVN 服务
svnserve -d -r /home/mysvn/rep
# svnserve -d -r 目录 --listen-port 端口号
-r
:配置方式决定了版本库访问方式。--listen-port
:指定SVN监听端口,不加此参数,SVN默认监听3690
由于 -r
配置方式的不一样,SVN 启动就可以有两种不同的访问方式
方式一:-r
直接指定到版本库(称之为单库 svnserve 方式)
svnserve -d -r /home/mysvn/rep
在这种情况下,一个 svnserve 只能为一个版本库工作。
authz 配置文件中对版本库权限的配置应这样写:
[groups]
admin=user1
dev=user2
[/]
@admin=rw
user2=r
使用类似这样的 URL:svn://192.168.211.129/
即可访问 rep 版本库
方式二:指定到版本库的上级目录(称之为多库 svnserve 方式)
svnserve -d -r /home/mysvn
这种情况,一个 svnserve 可以为多个版本库工作
authz 配置文件中对版本库权限的配置应这样写:
[groups]
admin=user1
dev=user2
[project01:/]
@admin=rw
user2=r
[project01:/]
@admin=rw
user2=r
如果此时你还用 [/]
,则表示所有库的根目录,同理,[/src]
表示所有库的根目录下的 src 目录。
使用类似这样的 URL:svn://192.168.211.129/project01
即可访问 project01 版本库。
SVN 客户端操作
SVN 检出操作
因为使用的是单库 svnserve 方式,所以无需指定地址
svn checkout svn://192.168.211.129/ --username=alsritter
status 状态
# 查看或目录状态
svn status
svn st
# 显示文件及子目录的状态,正常不显示
# ? 不在svn的控制中
# M 内容被修改
# C 发生冲突
# A 预订加入到版本库
# K 被锁定
add 添加
# 向版本库添加新文件
svn add a.txt
svn add *.txt
# 递归添加文件夹下所有内容
svn add b
# 已经添加的文件修改后无法添加,只能用commit
例如在本地库中增加一个 readme 的说明文件。
查看工作副本状态:
svn status
此时 readme 的状态为?,说明它还未加到版本控制中。
将文件 readme 加到版本控制,等待提交到版本库。
svn add readme
commit 提交
svn commit -m '注释内容' [-N] [--no-unlock] PATH
# 提交文件
svn commit -m 'add a.txt' a.txt
# 提交文件夹
svn commit -m 'add b' b
# 简写
svn ci
上面那节中添加文件后
此时 readme 的状态为A,它意味着这个文件已经被成功地添加到了版本控制中。
为了把 readme 存储到版本库中,使用 commit -m
加上注释信息来提交。
svn commit -m "SVN readme."
出现以下报错:
出现这种问题的原因在于搭建 SVN 服务器,包括创建 Repository 目录 /home/svn
目录下的一切子目录和文件都是在 root 用户下进行的,所以在 root 用户下检出、提交都没有问题。而如果使用其它用户提交则有问题
解决办法: 在服务器上把 Users 对 Repository 的完全控制权限加上就可以了,执行如下命令对 /home/svn
目录下的所有文件和子目录添加 Users 的读写权限
sudo chmod -R o+rw /home/mysvn
再次提交就畅通无阻了
update 更新
# 更新到最新版本
svn update
# 只更新某个特定文件
svn update a.txt
# 还原到指定版本
svn update -r 1
# 还原某个文件到指定版本
svn update -r 1 c.txt
# 简写
svn up
lock 锁
执行了 svn lock
命令,可以防止其他人进行提交。直到执行了锁定的用户执行了解锁命令
svn lock -m '加锁注释内容' [--force] PATH
# 加锁
svn lock -m "锁定文件" a.txt
# 解锁
svn unlock a.txt
delete 删除
# 删除版本库中文件
svn delete svn://127.0.0.1/demo/c.txt -m 'delete c.txt'
# 然后执行更新
svn update
# 推荐使用
svn delete c.txt
svn commit -m 'delete c.txt'
# 简写
svn (del, remove, rm)
revert 版本回退
当我们想放弃对文件的修改,可以使用 SVN revert 命令。
svn revert 操作将撤销任何文件或目录里的局部更改。
我们对文件 readme 进行修改,查看文件状态。
svn status
# 这时我们发现修改错误,要撤销修改,通过 svn revert 文件 readme 回归到未修改状态。
svn revert readme
进行 revert
操作之后,readme 文件恢复了原始的状态。 revert
操作不单单可以使单个文件恢复原状, 而且可以使整个目录恢复原状。恢复目录用 -R
命令,如下。
svn revert -R trunk
但是,假如我们想恢复一个已经提交的版本怎么办。
为了消除一个旧版本,我们必须撤销旧版本里的所有更改然后提交一个新版本。这种操作叫做 reverse merge
。
首先,找到仓库的当前版本,现在是版本 22,我们要撤销回之前的版本,比如版本 21。
svn merge -r 22:21 readme
diff 比较差异
# 比较当前修改和版本库中的差异
svn diff c.txt
# 版本之间对比
svn diff -r 1:2 a.txt
# 简写
svn di
merge 合并
# 将3版本和4版本合并到当前文件
svn merge -r 3:4 c.txt
# 但是一般都会产生冲突,需要处理一下
安装客户端
到官网下载这个 TortoiseSVN
安装好后:
新建本地仓库
本地仓库对应远程仓库即 SVN 服务器,本地仓库就是用于存放各种文档、程序的一个文件夹,在自己或别人编辑完后可通过 SVN 更新操作把最新版本的文件下载到本地仓库,或者通过 SVN 提交操作把自己的更改推送到服务器以方便他人获取
右键创建项目,输入远程仓库地址以绑定 SVN 服务器
svn://192.168.211.129/
输入用户名称密码后就拉取下来了
修改提交:
然后在弹出的界面中输入这次提交的备注信息
再在其它的客户端 Update 就能看到更新的信息了
测试冲突解决
这里在 Linux 的测试提交
在 Window 客户端上测试提交
然后显示冲突了
正确的做法是,点击这个 readme 文件,使用 TortoiseSVN 菜单里的【Edit conflicts】这个功能,编辑冲突。
工具自带的一个编辑窗口,主要分为三个部分,左上是指冲突的版本 12 文件的内容,右上是我们本地副本的内容(就是刚修改了,未提交的文件),最下面,是处理冲突合并后的效果。
这里提示的就是它们两个冲突,工具不知道如何自动合并,只能人工处理。我们最后修改的内容为【0000】,我们在右上的窗口这一行上面点击右键,选择【使用此块】,下面的合并窗口内容第一行,就会变为绿色(原来是红色的一行问号),如此类推,两边进行选择正确的代码就可以,重要的是【Merged】的窗口里的内容是我们想要的,就可以。
最后都处理完,下图上方红圆圈的地方【Maker as resolved】点击它,完成合并冲突。
此时,目录中的多余文件消失掉
再看下 readme 的内容,就是我们刚合并的内容,好了,冲突合并的解决流程就演示完成,下一步就可以提交文件,又回到基本的操作上。
SVN 查看历史信息
通过 svn 命令可以根据时间或修订号去除过去的版本,或者某一版本所做的具体的修改。以下四个命令可以用来查看svn 的历史:
- svn log:用来展示 svn 的版本作者、日期、路径等等。
- svn diff:用来显示特定修改的行级详细信息。
- svn cat:取得在特定版本的某文件显示在当前屏幕。
- svn list:显示一个目录或某一版本存在的文件。
log 日志
# 显示这个文件的修改记录,及版本号的变化(也可以直接显示全部文件变化)
svn log a.txt
如果只希望查看特定的某两个版本之间的信息,可以使用:
svn log -r 2:4
如果希望得到目录的信息要加 -v
。
如果希望显示限定 N 条记录的目录信息,使用 svn log -l N -v
svn log -l 5 -v
svn list
svn list 可以在不下载文件到本地目录的情况下来察看目录中的文件:
svn list http://192.168.0.1/
SVN 分支
在 SVN 上分支的概念比较弱,它没有专门的分支管理,都是自己维护分支的:
SVN 默认管理目录如下(自己手动创建):
通常 branches 目录下为开发分支,tags 目录为标签目录,trunk 为主目录。一般在开发目录下创建分支进行功能开发,开发完成并经过测试无bug,再合并到 trunk 目录。在合并之前应当先把当前 trunk 打一个 tag 作为备份。
我们在本地副本中创建一个 my_branch 分支。
# 在本地副本中创建一个 my_branch 分支
svn copy trunk/ branches/my_branch
提交新增的分支到版本库。
svn commit -m "add my_branch"
接着我们就到 my_branch 分支进行开发,切换到分支路径并创建 index.html
文件。
cd branches/my_branch/
将 index.html
加入版本控制,并提交到版本库中。
svn status
svn add index.html
svn commit -m "add index.html"
切换到 trunk,执行 svn update
,然后将 my_branch 分支合并到 trunk 中。
svn merge ../branches/my_branch/
此时查看目录,可以看到 trunk 中已经多了 my_branch 分支创建的 index.html
文件。
将合并好的 trunk 提交到版本库中。
svn commit -m "add index.html"
SVN 标签(tag)
同上分支,这个版本管理也是自己手动维护的
svn copy trunk/ tags/v1.0
ls tags/
ls tags/v1.0/
# 查看状态
svn status
# 提交tag内容。
svn commit -m "tags v1.0"